/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "rule_id_manager.h"
#include "netnative_log_wrapper.h"

namespace OHOS {
namespace nmd {
namespace {
constexpr int32_t RULE_LEVEL_VPN_OUTPUT_TO_LOCAL_BASE = 9000;
constexpr int32_t RULE_LEVEL_SECURE_VPN_BASE = 10000;
constexpr int32_t RULE_LEVEL_EXPLICIT_NETWORK_BASE = 11000;
constexpr int32_t RULE_LEVEL_OUTPUT_IFACE_VPN_BASE = 11500;
constexpr int32_t DEFAULT_START_RULE_ID = 10000;
constexpr int32_t DEFAULT_MAX_COUNT = 20;
constexpr int32_t RULEID_SUCESS = 0;
constexpr int32_t RULEID_FAILE = -1;
} // namespace

std::vector<RuleIdStatus> RuleIdManager::ruleLevelVpnOutputToLocal_;
std::vector<RuleIdStatus> RuleIdManager::ruleLevelSecureVpn_;
std::vector<RuleIdStatus> RuleIdManager::ruleLevelExplicitNetwork_;
std::vector<RuleIdStatus> RuleIdManager::ruleLevelOutputIfaceVpn_;

std::mutex RuleIdManager::vpnRuleIdLock_;
std::map<RuleIdManager::RuleType, uint32_t> RuleIdManager::vpnRuleId_;
std::map<RuleIdManager::RuleType, uint32_t> RuleIdManager::vpnRuleMaxCount_;

RuleIdManager::RuleIdManager()
{
}

int32_t RuleIdManager::Init()
{
    NETNATIVE_LOGI("RuleIdManager Init");
    InitRuleIds(RuleIdManager::RULE_LEVEL_VPN_OUTPUT_TO_LOCAL, RULE_LEVEL_VPN_OUTPUT_TO_LOCAL_BASE, DEFAULT_MAX_COUNT);
    InitRuleIds(RuleIdManager::RULE_LEVEL_SECURE_VPN, RULE_LEVEL_SECURE_VPN_BASE, DEFAULT_MAX_COUNT);
    InitRuleIds(RuleIdManager::RULE_LEVEL_EXPLICIT_NETWORK, RULE_LEVEL_EXPLICIT_NETWORK_BASE, DEFAULT_MAX_COUNT);
    InitRuleIds(RuleIdManager::RULE_LEVEL_OUTPUT_IFACE_VPN, RULE_LEVEL_OUTPUT_IFACE_VPN_BASE, DEFAULT_MAX_COUNT);
    return RULEID_SUCESS;
}

int32_t RuleIdManager::AddRuleId(RuleType type, int32_t startId, int32_t maxCount)
{
    std::lock_guard<std::mutex> lock(vpnRuleIdLock_);
    vpnRuleId_[type] = startId;
    vpnRuleMaxCount_[type] = maxCount;
    return RULEID_SUCESS;
}

int32_t RuleIdManager::GetStartRuleId(RuleType type)
{
    std::lock_guard<std::mutex> lock(vpnRuleIdLock_);
    auto iter = vpnRuleId_.find(type);
    if (iter != vpnRuleId_.end()) {
        return iter->second;
    }

    return DEFAULT_START_RULE_ID;
}

int32_t RuleIdManager::GetRuleIdMaxCount(RuleType type)
{
    std::lock_guard<std::mutex> lock(vpnRuleIdLock_);
    auto iter = vpnRuleMaxCount_.find(type);
    if (iter != vpnRuleMaxCount_.end()) {
        return iter->second;
    }

    return DEFAULT_MAX_COUNT;
}

int32_t RuleIdManager::InitRuleIds(RuleType type, int32_t startId, int32_t maxCount)
{
    NETNATIVE_LOGI("RuleIdManager InitRuleIds, startId = %{public}d, maxCount = %{public}d", startId, maxCount);
    int32_t ret = AddRuleId(type, startId-1, maxCount);

    switch(type) {
        case RuleIdManager::RULE_LEVEL_VPN_OUTPUT_TO_LOCAL:
            return InitRuleIds(type, ruleLevelVpnOutputToLocal_);
        case RuleIdManager::RULE_LEVEL_SECURE_VPN:
            return InitRuleIds(type, ruleLevelSecureVpn_);
        case RuleIdManager::RULE_LEVEL_EXPLICIT_NETWORK:
            return InitRuleIds(type, ruleLevelExplicitNetwork_);
        case RuleIdManager::RULE_LEVEL_OUTPUT_IFACE_VPN:
            return InitRuleIds(type, ruleLevelOutputIfaceVpn_);
        default:
            NETNATIVE_LOGE("rule type %{public}d is unknown type.", type);
            return RULEID_FAILE;
    }

    return ret;
}

int32_t RuleIdManager::InitRuleIds(RuleType type, std::vector<RuleIdStatus>& ruleIds)
{
    int32_t maxCount = GetRuleIdMaxCount(type);
    int32_t startId = GetStartRuleId(type);

    ruleIds.clear();
    ruleIds.resize(maxCount);

    for (int32_t i = 0; i < maxCount; i++) {
        ruleIds[i].used = false;
        ruleIds[i].deleted = false;
        ruleIds[i].ruleId = startId - i;
    }
    return RULEID_SUCESS;
}

int32_t RuleIdManager::GetNextRuleId(RuleType type)
{
    switch(type) {
        case RuleIdManager::RULE_LEVEL_VPN_OUTPUT_TO_LOCAL:
            return GetNextRuleId(type, ruleLevelVpnOutputToLocal_);
        case RuleIdManager::RULE_LEVEL_SECURE_VPN:
            return GetNextRuleId(type, ruleLevelSecureVpn_);
        case RuleIdManager::RULE_LEVEL_EXPLICIT_NETWORK:
            return GetNextRuleId(type, ruleLevelExplicitNetwork_);
        case RuleIdManager::RULE_LEVEL_OUTPUT_IFACE_VPN:
            return GetNextRuleId(type, ruleLevelOutputIfaceVpn_);
        default:
            NETNATIVE_LOGE("rule type %{public}d is unknown type.", type);
            return RULEID_FAILE;
    }
    return RULEID_SUCESS;
}

int32_t RuleIdManager::GetNextRuleId(RuleType type, std::vector<RuleIdStatus>& ruleIds)
{
    int32_t maxCount = GetRuleIdMaxCount(type);
    NETNATIVE_LOGI("GetNextRuleId,maxCount = %{public}d rule size = %{public}zu", maxCount, ruleIds.size());

    for (int i = 0; i <= maxCount; i++) {
        if (ruleIds[i].deleted) {
            ruleIds[i].deleted = false;
            ruleIds[i].used = true;
            return ruleIds[i].ruleId;
        }
    }

    for (int i = 0; i <= maxCount; i++) {
        if (!ruleIds[i].used) {
            ruleIds[i].used = true;
            return ruleIds[i].ruleId;
        }
    }

    return RULEID_FAILE;
}


int32_t RuleIdManager::DeleteRuleId(RuleType type, int32_t num)
{
    switch(type) {
        case RuleIdManager::RULE_LEVEL_VPN_OUTPUT_TO_LOCAL:
            return DeleteRuleId(type, ruleLevelVpnOutputToLocal_, num);
        case RuleIdManager::RULE_LEVEL_SECURE_VPN:
            return DeleteRuleId(type, ruleLevelSecureVpn_, num);
        case RuleIdManager::RULE_LEVEL_EXPLICIT_NETWORK:
            return DeleteRuleId(type, ruleLevelExplicitNetwork_, num);
        case RuleIdManager::RULE_LEVEL_OUTPUT_IFACE_VPN:
            return DeleteRuleId(type, ruleLevelOutputIfaceVpn_, num);
        default:
            NETNATIVE_LOGE("rule type %{public}d is unknown type.", type);
            return RULEID_FAILE;
    }
    return RULEID_SUCESS;
}

int32_t RuleIdManager::DeleteRuleId(RuleType type, std::vector<RuleIdStatus>& ruleIds, int32_t num)
{
    int32_t maxCount = GetRuleIdMaxCount(type);
    int32_t startId = GetStartRuleId(type);

    if (num > startId || num < startId - maxCount) {
        NETNATIVE_LOGE("delete rule id fail %{public}d", num);
        return RULEID_FAILE;
    }
    
    int index = startId - num;
    if (ruleIds[index].used && !ruleIds[index].deleted) {
        ruleIds[index].deleted = true;
    }
    return index;
}

} // namespace nmd
} // namespace OHOS
